/*
 * This file is part of the jquery plugin "asyncQueue".
 *
 * (c) Sebastien Roch <roch.sebastien@gmail.com>
 * @author (parallel) Dmitry Farafonov
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
(function ($) {
  $.AsyncQueue = function () {
    var that = this,
      queue = [],
      completeFunc,
      failureFunc,
      paused = false,
      lastCallbackData,
      _run,
      _complete,
      inQueue = 0,
      defaultTimeOut = 10;

    _run = function () {
      var f = queue.shift();

      if (f) {
        inQueue++;
        setTimeout(function () {
          f.fn.apply(that, [that]);

          if (!f.isParallel)
            if (paused === false) {
              _run();
            }
          inQueue--;
          if (inQueue == 0 && queue.length == 0) _complete();
        }, f.timeOut);

        if (f.isParallel)
          if (paused === false) {
            _run();
          }
      }
    };

    _complete = function () {
      if (completeFunc) completeFunc.apply(that, [that]);
    };

    this.onComplete = function (func) {
      completeFunc = func;
    };

    this.onFailure = function (func) {
      failureFunc = func;
    };

    this.add = function (func) {
      // TODO: add callback for queue[i] complete

      var obj = arguments[0];
      if (obj && Object.prototype.toString.call(obj) === '[object Array]') {
        var fn = arguments[1];
        var timeOut = typeof arguments[2] != 'undefined' ? arguments[2] : defaultTimeOut;
        if (typeof fn == 'function') {
          for (var i = 0; i < obj.length; i++) {
            var f = (function (objx) {
              queue.push({
                isParallel: true,
                fn: function () {
                  fn.apply(that, [that, objx]);
                },
                timeOut: timeOut,
              });
            })(obj[i]);
          }
        }
      } else {
        var fn = arguments[0];
        var timeOut = typeof arguments[1] != 'undefined' ? arguments[2] : defaultTimeOut;
        queue.push({ isParallel: false, fn: func, timeOut: timeOut });
      }
      return this;
    };

    this.addParallel = function (func, timeOut) {
      // TODO: add callback for queue[i] complete

      queue.push({ isParallel: true, fn: func, timeOut: timeOut });
      return this;
    };

    this.storeData = function (dataObject) {
      lastCallbackData = dataObject;
      return this;
    };

    this.lastCallbackData = function () {
      return lastCallbackData;
    };

    this.run = function () {
      paused = false;
      _run();
    };

    this.pause = function () {
      paused = true;
      return this;
    };

    this.failure = function () {
      paused = true;
      if (failureFunc) {
        var args = [that];
        for (i = 0; i < arguments.length; i++) {
          args.push(arguments[i]);
        }
        failureFunc.apply(that, args);
      }
    };

    this.size = function () {
      return queue.length;
    };

    return this;
  };
})(jQuery);
